﻿using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Steve.TestHelper;
using Steve.UI.Controllers;
using Steve.UI.Extensions;
using Steve.UI.Models;
using System.Collections.Generic;
using System;
using System.Web.Security;

namespace Steve.UI.Tests
{
    [TestClass]
    public class AccountController_Tests : ComposablePartTests
    {
        const string UserName = "thisisauser";
        const string ReturnUrl = "http://www.google.com/";

        protected override void InitializeGlobalTestData()
        {
        }

        [TestMethod]
        public void ArgumentNullException_Test()
        {
            var controller = this.ComposeController<AccountControllerBase>();
            ExceptionAssert.ThrowsArgumentNullException(() => controller.LogOnPost(null), "model");
        }

        [TestMethod]
        public void LogOff_Test()
        {
            AccountMock.Setup(a => a.SignOut()).Verifiable();

            var controller = this.ComposeController<AccountControllerBase>();

            var result = controller.LogOff();

            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));

            var typedResult = (RedirectToRouteResult)result;

            Assert.AreEqual("Home", typedResult.RouteName);

            AccountMock.Verify();
        }

        [TestMethod]
        public void LogOn_No_Return_Test()
        {
            AccountMock.Setup(a => a.GetUser()).Returns((MembershipUser)null).Verifiable();

            var controller = this.ComposeController<AccountControllerBase>();

            var result = controller.LogOn(ReturnUrl, null);

            Assert.IsInstanceOfType(result, typeof(ViewResult));

            var typedResult = (ViewResult)result;

            Assert.AreEqual("LogOn", typedResult.ViewName);
            Assert.IsInstanceOfType(typedResult.ViewData.Model, typeof(LogOnModel));

            var typedModel = (LogOnModel)typedResult.ViewData.Model;

            Assert.AreEqual(ReturnUrl, typedModel.ReturnUrl);
            Assert.IsTrue(string.IsNullOrWhiteSpace(typedModel.UserName));
            Assert.IsFalse(typedModel.IsUnauthenticatedUserName);

            AccountMock.Verify();
        }

        [TestMethod]
        public void LogOn_Return_User_Test()
        {
            var returnUser = new MembershipUser("AspNetSqlMembershipProvider", UserName, Guid.NewGuid(), "test@test.com", null, null, true, false
                , DateTime.Now.AddDays(-30)
                , DateTime.Now.AddDays(-5)
                , DateTime.Now.AddDays(-4.95)
                , DateTime.Now.AddDays(-30)
                , DateTime.MinValue);

            AccountMock.Setup(a => a.GetUser()).Returns(returnUser).Verifiable();

            var controller = this.ComposeController<AccountControllerBase>();

            var result = controller.LogOn(ReturnUrl, null);

            Assert.IsInstanceOfType(result, typeof(ViewResult));

            var typedResult = (ViewResult)result;

            Assert.AreEqual("LogOn", typedResult.ViewName);
            Assert.IsInstanceOfType(typedResult.ViewData.Model, typeof(LogOnModel));

            var typedModel = (LogOnModel)typedResult.ViewData.Model;

            Assert.AreEqual(ReturnUrl, typedModel.ReturnUrl);
            Assert.AreEqual(UserName, typedModel.UserName);
            Assert.IsTrue(typedModel.IsUnauthenticatedUserName);

            AccountMock.Verify();
        }

        [TestMethod]
        public void LogOn_NotMe_Test()
        {
            AccountMock.Setup(a => a.ClearUser()).Verifiable();

            var controller = this.ComposeController<AccountControllerBase>();

            var result = controller.LogOn(ReturnUrl, true);

            Assert.IsInstanceOfType(result, typeof(ViewResult));

            var typedResult = (ViewResult)result;

            Assert.AreEqual("LogOn", typedResult.ViewName);
            Assert.IsInstanceOfType(typedResult.ViewData.Model, typeof(LogOnModel));

            var typedModel = (LogOnModel)typedResult.ViewData.Model;

            Assert.AreEqual(ReturnUrl, typedModel.ReturnUrl);
            Assert.IsTrue(string.IsNullOrWhiteSpace(typedModel.UserName));
            Assert.IsFalse(typedModel.IsUnauthenticatedUserName);

            AccountMock.Verify();
        }


        [TestMethod]
        public void LogOnPost_Success_ReturnUrl_Test()
        {
            AccountMock.Setup(a => a.ValidateUser(UserName, "password")).Returns(true).Verifiable();
            AccountMock.Setup(a => a.SignIn(UserName)).Verifiable();

            var controller = this.ComposeController<AccountControllerBase>();

            var model = new LogOnModel() { UserName = UserName, Password = "password", ReturnUrl = ReturnUrl };

            var result = controller.LogOnPost(model);

            //TODO: how to handle validation???

            Assert.IsInstanceOfType(result, typeof(RedirectResult));

            var typedResult = (RedirectResult)result;

            Assert.AreEqual(ReturnUrl, typedResult.Url);

            AccountMock.Verify();
        }

        [TestMethod]
        public void LogOnPost_Success_No_ReturnUrl_Test()
        {
            AccountMock.Setup(a => a.ValidateUser(UserName, "password")).Returns(true).Verifiable();
            AccountMock.Setup(a => a.SignIn(UserName)).Verifiable();

            var controller = this.ComposeController<AccountControllerBase>();

            var model = new LogOnModel() { UserName = UserName, Password = "password" };

            var result = controller.LogOnPost(model);

            //TODO: how to handle validation???

            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));

            var typedResult = (RedirectToRouteResult)result;

            Assert.AreEqual("Home", typedResult.RouteName);

            AccountMock.Verify();
        }
    }
}
